﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Globalization;
using System.Data.Odbc;
using System.Threading;
using CallCheckerExceptions;
using DbSQLite;
using System.Linq;



namespace Callchecker
{
    public partial class FormMain : Form
    {
        #region Constructors

        public FormMain()
        {
            InitializeComponent();

        }

        #endregion

        #region События формы

        private void FormMain_Load(object sender, EventArgs e)
        {
            // Форма скрывается
            this.Visible = false;
            ShowInTaskbar = false;

            LoadProgramSettings();

            // Соединение с базой MySQL
            _dbMySql = new DbMySQL.DbFacadeMySQL(ProgramSettings.Item.Server, ProgramSettings.Item.Port, ProgramSettings.Item.MySqlAliase, 
                ProgramSettings.Item.MySqlPassword, ProgramSettings.Item.DatabaseName);
            // Запуск сервера выполнения запросов
            if (ProgramSettings.Item.StartOnLoad)
                StartTimer();
        }
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                this.Visible = false;
                this.ShowInTaskbar = false;
            }
        }

        #region Menu

        // Пункт "Файл"
        private void buttonSave_Click(object sender, EventArgs e) // Сохранение внесенных изменений по кнопке и по пункту меню
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                SaveProgramSettings();
                EnabeldSaveConrol(false);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }
        private void btnCancel_Click(object sender, EventArgs e) // Отмена изменений пользователя
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                LoadProgramSettings();
                EnabeldSaveConrol(false);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }
        private void tsmiExit_Click(object sender, EventArgs e) // Скрытие формы настроек
        {
            this.Visible = false;
            this.ShowInTaskbar = false;
        }
        private void btnStart_Click(object sender, EventArgs e) // Запуск или остановка сервера запросов
        {
            StartTimer();
        }

        // Пункт "Редактировать"
        // Переключение между вкладками. Один обработчик для всех пунктов
        private void tsmiEdit_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem ctrl = sender as ToolStripMenuItem;
            if ( ctrl != null)
            {
                switch (ctrl.Name)
                {
                    case "tsmiSettings":
                        tcMain.SelectedIndex = tcMain.TabPages.IndexOf(tpSettings);
                        RollEditEnabled("tsmiSettings");
                        break;
                    case "tsmiConnect":
                        tcMain.SelectedIndex = tcMain.TabPages.IndexOf(tpConnection);
                        RollEditEnabled("tsmiConnect");
                        break;
                    case "tsmiSql":
                        tcMain.SelectedIndex = tcMain.TabPages.IndexOf(tpSql);
                        RollEditEnabled("tsmiSql");
                        break;
                    default:
                        break;
                }
            }
        }
        private void tsmiHistoryMessage_Click(object sender, EventArgs e)
        {
            new FormHistoryMessage().Show();
        }

        // Пункт "Помощь"
        private void tsmiViewLog_Click(object sender, EventArgs e) // Просмотр лог-файла программы
        {
            try
            {
                Common.ShowLog();
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        } 
        private void tsmiOpenHelp_Click(object sender, EventArgs e) // Открытие файла справки
        {
            try
            {
                //System.Diagnostics.Process.Start(Common.HELP_PATH);
                Common.GetHelp("", HelpNavigator.TableOfContents);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }
        private void FormMain_HelpButtonClicked(object sender, CancelEventArgs e)
        {
            try
            {
                //System.Diagnostics.Process.Start(Common.HELP_PATH);
                Common.GetHelp("mf_settings", HelpNavigator.Topic);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }
        private void tsmiAbout_Click(object sender, EventArgs e) // Открытие формы "О программе"
        {
            new AboutBox().ShowDialog();
        }
        private void btnConnect_Click(object sender, EventArgs e)
        {
            SaveProgramSettings();

            _dbMySql = new DbMySQL.DbFacadeMySQL(ProgramSettings.Item.Server, ProgramSettings.Item.Port, ProgramSettings.Item.MySqlAliase,
                            ProgramSettings.Item.MySqlPassword, ProgramSettings.Item.DatabaseName);
            EnabeldSaveConrol(false);
        }
        private void FormMain_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F1)
            {
                try
                {
                    //System.Diagnostics.Process.Start(Common.HELP_PATH);
                    Common.GetHelp("mf_settings", HelpNavigator.Topic);
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message);
                }
            }
        }

        #endregion

        #region Окно в трее

        private void toolStripMenuItemProperties_Click(object sender, EventArgs e) // Пункт "Настройки"
        {
            this.Show();
            this.ShowInTaskbar = true;
        }
        private void toolStripMenuItemClose_Click(object sender, EventArgs e) // Пункт "Выход"
        {
            Application.Exit();
        }
        private void notifyIconMain_MouseDoubleClick(object sender, MouseEventArgs e) // Двойной клик по иконке в трее
        {
            toolStripMenuItemProperties_Click(null, null);
        }
        // Пункт "Помощь" обрабатывается обработчиком из меню
        // Пункт "История сообщений" обрабаытвается обработчиком из меню

        #endregion

        #region Закладки

        private void btnConnectTest_Click(object sender, EventArgs e) // Тест соединения с базой данных
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                DbMySQL.DbFacadeMySQL _checkDb = new DbMySQL.DbFacadeMySQL(tbServer.Text, (uint)nudPort.Value, tbLogin.Text, tbPassword.Text, tbBaseName.Text);
                if(_checkDb.CheckConnection)
                    MessageBox.Show(LogMessage.ShowMessageSuccessConnect);
                else
                    MessageBox.Show(LogMessage.ShowMessageErrorConnect);
                
                //TODO Реализовать тестирование соединения с сервером
                //MessageBox.Show(CommonString.TestConnectionOk);
            }
            catch (Exception err)
            {
                //TODO реализовать обработку исключения при невозможности соединения с сервером
                Log.ToLog(err.Message);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }
        private void valueChanged(object sender, EventArgs e) // Изменение значения NumericUpDown
        {
            EnabeldSaveConrol(true);
        }
        private void tcMain_TabIndexChanged(object sender, EventArgs e) // Изменение выбранной вкладки
        {
            RollEditEnabled(tcMain.TabPages[tcMain.SelectedIndex].Name);
        }

        #endregion


        #endregion 

        #region Вспомогательные методы

        /// <summary>
        /// Сохраняет данные формы настроек в класс настроек и затем на диск
        /// </summary>
        private void SaveProgramSettings()
        {
            // Установки
            ProgramSettings.Item.Interval = (int)nudActionFrequency.Value;
            ProgramSettings.Item.DurationOfInterval = (int)nudIntervalDuration.Value;
            timerMain.Interval = ProgramSettings.Item.Interval * 60000;
            ProgramSettings.Item.NormalMissedCall = (int)nudNormal.Value;
            ProgramSettings.Item.ActivatedAlarm = cbCheckAlarm.Checked;
            ProgramSettings.Item.StartOnLoad = cbStartOnLoad.Checked;
            ProgramSettings.Item.TimeShift = (int)nudTimeShift.Value;
            ProgramSettings.Item.StartOnLoadOS = cbStartOnLoadOS.Checked;
            if (ProgramSettings.Item.StartOnLoadOS && !ShortCuts.IsServiceRegistered)
                ShortCuts.Register();
            if (!ProgramSettings.Item.StartOnLoadOS && ShortCuts.IsServiceRegistered)
                ShortCuts.UnRegister();

            // Настройки соединения с базой
            ProgramSettings.Item.Server = tbServer.Text;
            ProgramSettings.Item.Port = (uint)nudPort.Value;
            ProgramSettings.Item.TypeConnection = cbTypeConnection.Text;
            ProgramSettings.Item.DatabaseName = tbBaseName.Text;
            ProgramSettings.Item.MySqlPassword = tbPassword.Text;
            ProgramSettings.Item.MySqlAliase = tbLogin.Text; 

            // Настройка запросов к базе
            ProgramSettings.Item.SqlString.Clear();
            ProgramSettings.Item.SqlString.Add(tbSql.Text);

            ProgramSettings.Save();
        }

        /// <summary>
        /// Сохраняет данные настроек из файла в класс настроек и затем обновляет форму
        /// </summary>
        private void LoadProgramSettings()
        {
            ProgramSettings.Load();
            
            // Установки
            nudActionFrequency.Value = ProgramSettings.Item.Interval;
            nudIntervalDuration.Value = ProgramSettings.Item.DurationOfInterval;
            nudNormal.Value = ProgramSettings.Item.NormalMissedCall;
            cbCheckAlarm.Checked = ProgramSettings.Item.ActivatedAlarm;
            cbStartOnLoad.Checked = ProgramSettings.Item.StartOnLoad;
            nudTimeShift.Value = ProgramSettings.Item.TimeShift;
            cbStartOnLoadOS.Checked = ShortCuts.IsServiceRegistered;

            // Настройки соединения с базой
            tbServer.Text = ProgramSettings.Item.Server;
            nudPort.Value = ProgramSettings.Item.Port;
            cbTypeConnection.Text = ProgramSettings.Item.TypeConnection;
            tbBaseName.Text = ProgramSettings.Item.DatabaseName;
            tbLogin.Text = ProgramSettings.Item.MySqlAliase;
            tbPassword.Text = ProgramSettings.Item.MySqlPassword; 

            // Настройка запросов к базе
            if (ProgramSettings.Item.SqlString.Count > 0)
                tbSql.Text = ProgramSettings.Item.SqlString[0];
            else
                tbSql.Text = "";

            EnabeldSaveConrol(false);
        }
        
        private void StartTimer()
        {
            if (timerMain.Enabled)
            {
                timerMain.Stop();
                btnStart.Text = LogMessage.ButtonStart;
                lbStatus.Text = LogMessage.ServerIsStoping;
            }
            else
            {
                btnStart.Text = LogMessage.ButtonStop;
                lbStatus.Text = LogMessage.ServerIsStarting;
                timerMain.Interval = ProgramSettings.Item.Interval * 60000;
                timerMain.Start();
            }
        }
        private void timerMain_Tick(object sender, EventArgs e)
        {
            AbortableBackgroundWorker bw = new AbortableBackgroundWorker();
            bw.DoWork += GetData;
            bw.RunWorkerCompleted += bw_RunWorkerCompleted;
            bw.RunWorkerAsync();

            // Проверка ярлыка в автозапуске
            cbStartOnLoadOS.Checked = ShortCuts.IsServiceRegistered;
            EnabeldSaveConrol(false);
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Common.ShowNotify(notifyIconMain, LogMessage.ShowTitleError, LogMessage.ShowMessageErrorConnect, ToolTipIcon.Error);
                throw new CCException(ErrType.Notify, LogMessage.ShowMessageErrorConnect);
            }
        }
        private void GetData(object sender, DoWorkEventArgs e)
        {
            // Проверка соединения
            if (!_dbMySql.CheckConnection)
                throw new CCException(ErrType.Notify, LogMessage.ShowMessageErrorConnect);

            // Получение данных из базы
            DbMySQL.ParametersCollection parameters = new DbMySQL.ParametersCollection();
            DateTime currentTime = DateTime.Now.AddHours(ProgramSettings.Item.TimeShift);
            parameters.Add("@df", currentTime.AddHours(-ProgramSettings.Item.DurationOfInterval), MySql.Data.MySqlClient.MySqlDbType.DateTime);
            parameters.Add("@dt", currentTime, MySql.Data.MySqlClient.MySqlDbType.DateTime);
            DataTable dt = _dbMySql.Execute(tbSql.Text, parameters);

            List<CallOfTimes> ls = new List<CallOfTimes>();
            // Разбивка по часам
            if (dt.Rows.Count > 0)
            {
                for (int i = 0; i < ProgramSettings.Item.DurationOfInterval; i++)
                {
                    var results = from myRow in dt.AsEnumerable()
                                  where myRow.Field<DateTime>("calldate") <= currentTime.AddHours(-i) && myRow.Field<DateTime>("calldate") >= currentTime.AddHours(-i - 1)
                                  select myRow.Field<DateTime>("calldate");
                    ls.Add(new CallOfTimes() { Df = currentTime.AddHours(-i - 1), Dt = currentTime.AddHours(-i), Count = results.Count() });
                }
                int cntMax = ls.Select(n => n.Count).Max();
                int cntSum = ls.Select(n => n.Count).Sum();

                string sl = ls.Select(n => String.Format("За период c {0} по {1} пропущено {2} звонков. ", n.Df, n.Dt, n.Count)).Aggregate((curr, next) => curr + "\r\n" + next).ToString();
                sl = String.Format("{0}\r\n{1}\r\n{2}", sl, String.Format("Максимальное число записей = {0}", cntMax), String.Format("Всего записей за преиод {0} часов = {1}", ProgramSettings.Item.DurationOfInterval, cntSum));

                Log.ToLog(sl);
                SQ_Message sq = new SQ_Message()
                {
                    DT = currentTime,
                    MSG = String.Format("За период с {0} по {1} было пропущено {2} звонков. Максимальное количество пропущенных звонков - {3} в час.",
                    currentTime.AddHours(-ProgramSettings.Item.DurationOfInterval), currentTime, cntSum, cntMax),
                    DETAILS = sl
                };
                sq.SaveToDb();

                if (cntMax > ProgramSettings.Item.NormalMissedCall)
                    ShowWarrning(cntSum, currentTime.AddHours(-ProgramSettings.Item.DurationOfInterval), currentTime, cntMax);
            }
        }

        private void ShowWarrning(int cnt, DateTime df, DateTime dt, int maxCnt)
        {
            Common.ShowNotify(notifyIconMain, LogMessage.ShowTitleMessage, LogMessage.ShowWarning, ToolTipIcon.Warning);
            notifyIconMain.Visible = true;
            notifyIconMain.ShowBalloonTip(CallChecker.Default.ToolTipeShowTime);

            if (ProgramSettings.Item.ActivatedAlarm)
                Common.PlayAlarm(null);

        }
        private void EnabeldSaveConrol(bool enabled)
        {
            btnSave.Enabled = enabled;
            btnCancel.Enabled = enabled;
            tsmiSaveChange.Enabled = enabled;
            tsmiCancelChange.Enabled = enabled;
        }
        private void RollEditEnabled(string tabName)
        {
            switch (tabName)
            {
                case "tsmiSettings":
                case "tpSettings":
                    tsmiSettings.Enabled = false;
                    tsmiSql.Enabled = true;
                    tsmiConnect.Enabled = true;
                    break;
                case "tsmiConnect":
                case "tpConnection":
                    tsmiSettings.Enabled = true;
                    tsmiSql.Enabled = true;
                    tsmiConnect.Enabled = false;
                    break;
                case "tsmiSql":
                case "tpSql":
                    tsmiSettings.Enabled = true;
                    tsmiSql.Enabled = false;
                    tsmiConnect.Enabled = true;
                    break;
                default:
                    break;
            }
         
        
        }

        #endregion

        /// <summary>
        /// Экземпляр класса для работы с базой данных MySQL
        /// </summary>
        public static DbMySQL.DbFacadeMySQL _dbMySql;
 
        /// <summary>
        /// Структура предназначена для сохранения предварительных данных о количестве звонков в запросе
        /// </summary>
        private struct CallOfTimes
        {
            public DateTime Df { get; set; }
            public DateTime Dt { get; set; }
            public int Count { get; set; }
        }

   }
}
